import os
import sys
import re
import urllib
from datetime import datetime
from mimetypes import types_map
import logging

import webapp2
from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import db

import AppEnv
import base.RequestHandler
import base.Error
import base.Role
import base.Decorators
import models.Blog
import models.Post
import models.Comment
import models.Tag
import models.TrackBack
import models.Theme
import utils
import lib.PyRSS2Gen
import widgets

# the blogid_re to get blogid from self.reqpath
blogid_re = re.compile(r'/(?P<blogid>\w+)(?P<blogpath>(/.*)*)')

class GlogIndexPage(base.RequestHandler.PageRequestHandler):
    def get(self):
        extraPath = None
        if self.reqpath.startswith('/archive/'):
            #archive
            ar = self.reqpath[len('/archive/'):]
            m = re.match(r'(?P<year>\d{4})/(?P<month>\d{2})$',ar)
            if m:
                year = int(m.group('year'))
                month = int(m.group('month'))
                if month<1 or month >12:
                    self.renderErrorPage(base.Error.PageNotFoundError(),404)
                    return
                sdt = datetime(year,month,1)
                if month==12:
                    edt = datetime(year+1,1,1)
                else:
                    edt = datetime(year,month+1,1)
                posts = models.Post.Post.all().filter('published = ',True).filter('date >= ',sdt).filter('date < ',edt).order('-date').fetch(limit=100)
                extraPath = 'Archive:%04d-%02d' % (year, month)
            else:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        elif self.reqpath.startswith('/tag/'):
            #tag
            tag = self.reqpath[len('/tag/'):]
            tag = utils.urlString2PageString(tag)

            posts = models.Post.Post.all().filter('published = ',True).filter('tags = ',utils.toDBString(tag)).order('-date').fetch(limit=1000)
            extraPath = 'Tag:' + tag
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        else:
            posts = models.Post.Post.all().filter('published = ',True).order('-date').fetch(limit=self.appconfig.postsPerPage)

        # all archives
        arlist = models.Post.getArlist()

        # all tags
        taglist = models.Tag.getTaglist()

        # all blogs
        bloglist = models.Blog.Blog.all().fetch(limit=1000)
        
        if extraPath:
            self.templatedic['extraPath'] = extraPath
        self.templatedic['arlist'] = arlist
        self.templatedic['taglist'] = taglist
        self.templatedic['bloglist'] = bloglist
        self.templatedic['postlist'] = posts
        self.render(models.Theme.AppIndex_page)
        return

    def post(self):
        return self.get()
    
class GlogRssFeed(base.RequestHandler.PageRequestHandler):
    def get(self,*groups):
        fetcher = models.Post.Post.all().filter('published = ',True)
        tag = None
        if self.reqpath.startswith('/rss/tag/'):
            #tag
            tag = self.reqpath[len('/rss/tag/'):]
            tag = utils.urlString2PageString(tag)

            fetcher = fetcher.filter('tags = ',utils.toDBString(tag))
        
        posts = fetcher.order('-date').fetch(limit=self.appconfig.rssCount)

        rssItems = []
        for post in posts:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, post.blog.blogId, post.uid)
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = post.title,
                    author = utils.toPageString(post.blog.owner.nickname()),
                    link = post_url,
                    description = post.content,
                    pubDate = post.date,
                    guid = lib.PyRSS2Gen.Guid(post_url),
                    categories = post.tags
                    )
            )

        title = self.appname
        link = '%s%s' %  (self.appconfig.HostURL, self.apppath)
        if tag:
            title = title + ':' + utils.toPageString(tag)
            link = link + '/tag/%s' % utils.pageString2UrlString(tag)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d posts of %s' % (min(len(rssItems), self.appconfig.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class GlogCommentFeed(base.RequestHandler.PageRequestHandler):
    def get(self,*groups):
        fetcher = models.Comment.Comment.all()
        
        comments = fetcher.order('-date').fetch(limit=self.appconfig.rssCount)

        rssItems = []
        for comment in comments:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, comment.post.blog.blogId, comment.post.uid)
            comment_url = post_url + '#c%s' % comment.key().id()
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = comment.title,
                    author = utils.toPageString(comment.author.nickname()),
                    link = comment_url,
                    description = '%s reply to <a href="%s">%s</a>:<br/> %s' % (utils.toPageString(comment.author.nickname()),
                                                                                utils.toPageString(post_url),
                                                                                utils.toPageString(comment.post.title),
                                                                                utils.toPageString(comment.content)),
                    pubDate = comment.date,
                    guid = lib.PyRSS2Gen.Guid(comment_url),
                    )
            )

        title = self.appname
        link = '%s%s' %  (self.appconfig.HostURL, self.apppath)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d comments of %s' % (min(len(rssItems), self.appconfig.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           
    
class PostList(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True)
        if self.blogpath.startswith('/archive/'):
            #archive
            ar = self.blogpath[len('/archive/'):]
            m = re.match(r'(?P<year>\d{4})/(?P<month>\d{2})$',ar)
            if m:
                year = int(m.group('year'))
                month = int(m.group('month'))
                if month<1 or month >12:
                    self.renderErrorPage(base.Error.PageNotFoundError(),404)
                    return
                sdt = datetime(year,month,1)
                if month==12:
                    edt = datetime(year+1,1,1)
                else:
                    edt = datetime(year,month+1,1)
                posts = fetcher.filter('date >= ',sdt).filter('date < ',edt).order('-date').fetch(limit=100)
                extraPath = 'Archive:' + str(year) + '-' + str(month)
            else:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        elif self.blogpath.startswith('/tag/'):
            #tag
            tag = self.blogpath[len('/tag/'):]
            tag = utils.urlString2PageString(tag)
            posts = fetcher.filter('tags = ',utils.toDBString(tag)).order('-date').fetch(limit=1000)
            extraPath = 'Tag:' + tag
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
        else:
            posts = fetcher.order('-date').fetch(limit=self.blog.postsPerPage)
            extraPath = None
        if extraPath:
            self.templatedic['extraPath'] = extraPath
        self.templatedic['postlist'] = posts
        self.render(models.Theme.PostList_page)
        return
    
class PostSummary(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        if self.is_blogowner:
            fetcher = models.Post.Post.all().filter('blog = ', self.blog).order('-date')
        else:
            fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).order('-date')

        smrypath = self.blogpath[len('/summary'):]
        extraPath = None
        extraURL = ''

        if smrypath.startswith('/tag/'):
            # tag
            smrypath = smrypath[len('/tag'):]
            l = smrypath.split('/',2)
            if len(l)>2:
                smrypath = '/' + l[2]
            elif len(l)>1:
                smrypath = '/'
            else:
                raise base.Error.PageNotFoundError()
            
            if len(l)>1:
                tag = l[1]
                tag = utils.urlString2PageString(tag)
                fetcher = fetcher.filter('tags = ', utils.toDBString(tag))
                extraPath = 'Tag:%s' % tag
                extraURL = 'tag/%s/' % tag
        elif smrypath.startswith('/ar/'):
            # archive
            smrypath = smrypath[len('/ar'):]
            l = smrypath.split('/',3)
            if len(l)>3:
                smrypath = '/' + l[3]
            elif len(l)>2:
                smrypath = '/'
            else:
                raise base.Error.PageNotFoundError()
            
            if len(l)>2:
                ar = '/'.join(l[1:3])
                m = re.match(r'(?P<year>\d{4})/(?P<month>\d{2})$',ar)
                if not m:
                    raise base.Error.PageNotFoundError()
                else:
                    year = int(m.group('year'))
                    month = int(m.group('month'))
                    if month<1 or month >12:
                        raise base.Error.PageNotFoundError()
                    sdt = datetime(year,month,1)
                    if month==12:
                        edt = datetime(year+1,1,1)
                    else:
                        edt = datetime(year,month+1,1)
                    fetcher = fetcher.filter('date >= ',sdt).filter('date < ',edt)
                    extraPath = 'Archive:%04d-%02d' % (year, month)
                    extraURL = 'ar/%s/' % ar

        curpage = 1
        if smrypath == '/' or smrypath == '':
            curpage = 1
        else:
            m = re.match(r'/(?P<page>\d{1,4})$',smrypath)
            if m:
                curpage = int(m.group('page'))
            else:
                raise base.Error.PageNotFoundError()
        count = fetcher.count()

        if self.blog.postsPerPageList * curpage < 1 or self.blog.postsPerPageList * (curpage-1)>count:
            raise base.Error.PageNotFoundError()
        else:
            prepage = curpage -1
            if self.blog.postsPerPageList * curpage >= count:
                nextpage = 0
            else:
                nextpage = curpage + 1

        posts = fetcher.fetch(limit=self.blog.postsPerPageList, offset=self.blog.postsPerPageList*(curpage-1) )
            
        self.templatedic['postlist'] = posts
        self.templatedic['prepage'] = prepage
        self.templatedic['nextpage'] = nextpage
        self.templatedic['extraPath'] = extraPath
        self.templatedic['extraURL'] = extraURL
        self.templatedic['taglist'] = models.Tag.getTaglist(owner=self.blog)
        self.templatedic['arlist'] =  models.Post.getArlist(blog=self.blog, getCount=False)

        self.render(models.Theme.PostSummary_page)
        return
        
class RssFeed(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self, *groups):
        fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True)
        tag = None
        if self.blogpath.startswith('/rss/tag/'):
            #tag
            tag = self.blogpath[len('/rss/tag/'):]
            tag = utils.urlString2PageString(tag)

            fetcher = fetcher.filter('tags = ',utils.toDBString(tag))
        
        posts = fetcher.order('-date').fetch(limit=self.blog.rssCount)

        rssItems = []
        for post in posts:
            post_url = '%s%s/%s/post/%s' % (self.appconfig.HostURL, self.apppath, post.blog.blogId, post.uid)
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = post.title,
                    author = utils.toPageString(post.blog.owner.nickname()),
                    link = post_url,
                    description = post.content,
                    pubDate = post.date,
                    guid = lib.PyRSS2Gen.Guid(post_url),
                    categories = post.tags
                    )
            )

        title = self.blog.blogName
        link = '%s%s/%s' %  (self.appconfig.HostURL, self.apppath, self.blog.blogId)
        if tag:
            title = title + ':' + utils.toPageString(tag)
            link = link + '/tag/%s' % utils.pageString2UrlString(tag)
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d posts of %s' % (min(len(rssItems), self.blog.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class CommentFeed(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self, *groups):
        uid = self.blogpath[len('/rss/comment/'):]
        if uid:
            # post
            uid = utils.urlString2uid(uid)

            posts = models.Post.Post.all().filter('uid = ',uid).fetch(limit=1)
            if not posts:
                self.renderErrorPage(base.Error.PageNotFoundError(),404)
                return
            post = posts[0]
            comments = [db.get(k)for k in post.comments[:self.blog.rssCount] ]
        else:
            comments = models.Comment.Comment.all().filter(' blog = ', self.blog).order('-date').fetch(limit=self.blog.rssCount)

        rssItems = []
        for comment in comments:
            post_url = '%s%s/%s/post/%s' % (utils.toPageString(self.appconfig.HostURL), self.apppath, utils.toPageString(comment.post.blog.blogId), comment.post.uid)
            comment_url = post_url + '#c%s' % comment.key().id()
            rssItems.append(lib.PyRSS2Gen.RSSItem(
                    title = utils.toPageString(comment.title),
                    author = utils.toPageString(comment.author.nickname()),
                    link = comment_url,
                    description = '%s reply to <a href="%s">%s</a>:<br/> %s' % (utils.toPageString(comment.author.nickname()),
                                                                                utils.toPageString(post_url),
                                                                                utils.toPageString(comment.post.title),
                                                                                utils.toPageString(comment.content)),
                    pubDate = comment.date,
                    guid = lib.PyRSS2Gen.Guid(comment_url),
                    )
            )

        if uid:
            # comments of a post
            title = 'Comments of %s' % utils.toPageString(post.title)
            link = '%s%s/%s/%s' % (self.appconfig.HostURL, self.apppath, self.blog.blogId, post.uid)
        else:
            # comment of the blog
            title = 'Comments of %s' % self.blog.blogName
            link = '%s%s/%s' %  (self.appconfig.HostURL, self.apppath, self.blog.blogId)
            
        rss = lib.PyRSS2Gen.RSS2(
                    title = title,
                    link = link,
                    description = 'latest %d comments of %s' % (min(len(rssItems), self.blog.rssCount), title),
                    lastBuildDate = datetime.utcnow(),
                    items = rssItems
                    )

        self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
        self.write(rss.to_xml(encoding='utf-8'))           

class NewPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        self.render(models.Theme.EditPost_page)
        return

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        user = users.get_current_user()

        errmsg = ''
        infomsg = ''
        uid = ''
        haserr = True
        while True:
            #references
            rfcount = int(self.param('referencecount'))
            rfs = []
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    rfs.append(url)
            references = []            
            flag = False
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    try:
                        references.append(db.Link(url))
                    except db.BadValueError,e:
                        errmsg = 'Reference "%s" is not a valid URL' % url
                        flag = True
                        break
            if flag:
                break
            #title
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = models.Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            #content
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = models.Post.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break
            #published
            published = self.param('published') == '1'
            #tags
            tags = models.Tag.split_tags(utils.stripUnsafeTag(self.param('tags')))
            
            uid = models.Post.new_post(author=self.blog,
                                title=title,
                                content=content,
                                tags=tags,
                                references=references,
                                publish = published)

            if not published:
                infomsg = 'Post saved'
            haserr = False
            break
        if haserr or not published:
            self.templatedic['title'] = self.param('title')
            self.templatedic['uid'] = uid
            self.templatedic['content'] = self.param('content')
            self.templatedic['published'] = self.param('published') == '1'
            self.templatedic['referencelist'] = rfs
            self.templatedic['tags'] = models.Tag.split_tags(self.param('tags'))
            self.templatedic['errmsg'] = errmsg
            self.templatedic['infomsg'] = infomsg
            self.render(models.Theme.EditPost_page)
            return
        else:
            self.redirect('/blog/post/%s' % uid)
            
class EditPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        user = users.get_current_user()

        uid = self.blogpath[len('/edit/'):]
        uid = utils.urlString2uid(uid)

        posts = models.Post.Post.all().filter('uid = ',uid).fetch(limit=1)
        if not posts:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)
            return
        else:
            post = posts[0]
            self.templatedic['title'] = post.title
            self.templatedic['uid'] = post.uid
            self.templatedic['content'] = post.content
            self.templatedic['published'] = post.published
            self.templatedic['referencelist'] = post.references
            self.templatedic['tags'] = post.tags
            self.templatedic['errmsg'] = ''
            self.render(models.Theme.EditPost_page)
            return

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        user = users.get_current_user()

        errmsg = ''
        infomsg = ''
        haserr = True
        while True:
            #references
            rfcount = int(self.param('referencecount'))
            rfs = []
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    rfs.append(url)
            references = []
            flag = False
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    try:
                        references.append(db.Link(url))
                    except db.BadValueError,e:
                        errmsg = 'Reference "%s" is not a valid URL' % url
                        flag = True
                        break
            if flag:
                break
            #uid
            uid = self.param('uid')
                
            #title
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = models.Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            #content
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = models.Post.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break
            #published
            published = self.param('published') == '1'
            #tags
            tags = models.Tag.split_tags(utils.stripUnsafeTag(self.param('tags')))

            try:
                models.Post.edit_post(blog=self.blog,
                               uid = uid,
                               title=title,
                               content=content,
                               tags=tags,
                               references=references,
                               publish=published)
            except base.Error.PageNotFoundError,e:
                self.renderErrorPage(e,404)
                return
            if not published:
                infomsg = 'Post saved'
            haserr = False
            break
        if haserr or not published:
            self.templatedic['title'] = self.param('title')
            self.templatedic['uid'] = self.param('uid')
            self.templatedic['content'] = self.param('content')
            self.templatedic['published'] = published
            self.templatedic['tags'] = models.Tag.split_tags(self.param('tags'))
            self.templatedic['errmsg'] = errmsg
            self.templatedic['infomsg'] = infomsg
            self.render(models.Theme.EditPost_page)
            return
        else:
            self.redirect('%s/%s/post/%s' % (AppEnv.app_root, self.blogid, uid))

class ViewPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        uid = self.blogpath[len('/post/'):]
        uid = utils.urlString2uid(uid)
        fetcher = models.Post.Post.all().filter('blog = ', self.blog).filter('uid = ',uid)
        if not self.is_blogowner:
            fetcher = fetcher.filter('published = ',True)
        posts = fetcher.fetch(limit=1)
        if posts:
            post = posts[0]
            commentList = []
            for comment in post.comments:
                commentList.append(db.get(comment))
            trackbacks = []
            #for tb in post.trackbacks:
            #    trackbacks.append(db.get(tb))
            #pre and next post
            posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('date < ',post.date).order('-date').fetch(limit=1)
            if posts:
                prepost = posts[0]
            else:
                prepost = None
            posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('date > ',post.date).order('date').fetch(limit=1)
            if posts:
                nextpost = posts[0]
            else:
                nextpost = None
            self.templatedic['post'] = post
            self.templatedic['commentList'] = commentList
            self.templatedic['trackbacks'] = trackbacks
            self.templatedic['prepost'] = prepost
            self.templatedic['nextpost'] = nextpost
            self.render(models.Theme.ViewPost_page)
        else:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)
            
class DeletePost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        uid = self.blogpath[len('/del/'):]
        uid = utils.urlString2uid(uid)

        try:
            models.Post.delete_post(uid = uid)
        except base.Error.PageNotFoundError,e:
            self.renderErrorPage(e,404)
            return

        self.redirect('%s/%s' % (self.apppath, self.blogid))
            
class AddComment(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.GUser)
    def post(self):
        user = users.get_current_user()
        
        uid = self.request.path[len('/blog/comment/'):]
        uid = utils.urlString2uid(uid)
        posts = models.Post.Post.all().filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
        if posts:
            post = posts[0]
            haserr = True
            while True:
                title = self.param('title')
                title = utils.stripUnsafeTag(title)
                cr = models.Comment.checkTitle(title)
                if not cr[0]:
                    errmsg = cr[1]
                    break
                content = self.param('content')
                content = utils.stripUnsafeTag(content)
                cr = models.Comment.checkContent(content)
                if not cr[0]:
                    errmsg = cr[1]
                    break

                comment = models.Comment.add_comment(post, user, title, content)
                
                haserr = False
                break
            if haserr:
                self.renderErrorPage(errmsg)
                return
            self.redirect('/blog/post/%s' % uid)
        else:
            self.renderErrorPage(base.Error.PageNotFoundError(),404)

class TrackPost(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        self.templatedic['errmsg'] = 'GET method is not supported for ping on this blog, use POST instead please.'
        self.render(models.Theme.FailedPingEcho_xml, default=True)
        return 
    
    @base.Decorators.blogRequest(blogid_re)
    def post(self):
        errmsg = ''

        uid = self.blogpath[len('/track/'):]
        uid = utils.urlString2uid(uid)
        posts = models.Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
        if posts:
            post = posts[0]
            while True:
                title = self.param('title')
                if len(title) > 200:
                    errmsg = 'invalid track back (%s)'%'title too long'
                    break
                blog_name = self.param('blog_name')
                if len(title) > 200:
                    errmsg = 'invalid track back (%s)'%'blog_name too long'
                    break
                try:
                    url = db.Link(self.param('url'))
                    tbs =  models.TrackBack.TrackBack.all().filter('post = ', post).filter(' url = ',url).fetch(limit=1)
                    if not tbs:
                        tb = models.TrackBack.TrackBack(post = post,
                                                        title = utils.toDBString(title),
                                                        blog_name = utils.toDBString(blog_name),
                                                        url = url)
                        tb.put()
                        post.trackbacks.append(tb.key())
                        post.put()
                    # FixMe TrackBack and Post should be n:m relatinship,
                    # here I assume a url ping only one post in our blog system(which is almost wrong).
                except db.BadValueError:
                    errmsg = 'invalid track back (%s)'%'bad url'
                
                break
        else:
            errmsg = 'Page Does not Exists(You want fool me?)'

        if errmsg:
            self.templatedic['errmsg'] = errmsg
            self.render(models.Theme.FailedPingEcho_xml, default=True)
            return
        else:
            self.render(models.Theme.SucceedPingEcho_xml, default=True)
            return 
    
class Settings(base.RequestHandler.PageRequestHandler):
    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def get(self):
        self.templatedic['blogName'] = self.blog.blogName
        self.templatedic['blogDesc'] = self.blog.blogDesc
        self.templatedic['postsPerPage'] = self.blog.postsPerPage
        self.templatedic['rssCount'] = self.blog.rssCount
        self.templatedic['postsPerPageList'] = self.blog.postsPerPageList
        self.templatedic['themename'] = self.blog.theme.name
        self.templatedic['themelist'] = models.Theme.getAllThemes()
        self.templatedic['widgets'] = '\n'.join(self.blog.widgets)
        self.render(models.Theme.Settings_page)
        return 

    @base.Decorators.blogRequest(blogid_re)
    @base.Decorators.needRole(base.Role.Blogowner)
    def post(self):
        #is reset?
        if self.param('submit') == 'reset':
            self.blog.reset()
            self.blog.put()
            self.templatedic['infomsg'] = 'Settings reset'
            self.templatedic['blogName'] = self.blog.blogName
            self.templatedic['blogDesc'] = self.blog.blogDesc
            self.templatedic['postsPerPage'] = self.blog.postsPerPage
            self.templatedic['rssCount'] = self.blog.rssCount
            self.templatedic['postsPerPageList'] = self.blog.postsPerPageList
            self.templatedic['themename'] = self.blog.theme.name
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = '\n'.join(self.blog.widgets)

            self.theme = self.blog.theme
            self.templatedic['theme'] = self.theme
            
            self.render(models.Theme.Settings_page)
            return 

        errmsg = ''
        infomsg = ''
        haserr = True
        while True:
            blogDesc = self.param('blogDesc')
            blogDesc = utils.stripUnsafeTag(blogDesc)

            blogName = self.param('blogName')
            blogName = utils.stripUnsafeTag(blogName)
            cr = models.Blog.checkblogName(blogName)
            if not cr[0]:
                errmsg = cr[1]
                break
                            
            postsPerPage = self.param('postsPerPage')
            cr = models.Blog.checkpostsPerPage(postsPerPage)
            if not cr[0]:
                errmsg = cr[1]
                break
            rssCount = self.param('rssCount')
            cr = models.Blog.checkrssCount(rssCount)
            if not cr[0]:
                errmsg = cr[1]
                break
            postsPerPageList = self.param('postsPerPageList')
            cr = models.Blog.checkpostsPerPageList(postsPerPageList)
            if not cr[0]:
                errmsg = cr[1]
                break
            # Theme
            themename = self.param('themename')
            theme = models.Theme.getTheme(themename)
            if not theme:
                errmsg = 'no this theme'
                break
            # widgets
            try:
                widgets = models.Blog.parseWidgets(self.param('widgets'))
            except base.Error.InvalidWidgetIdError,e:
                errmsg = str(e)
                break
            # API Password
            changeAPIPass = self.param('changeAPIPass')
            if changeAPIPass:
                apiPass = self.param('apiPass')
                cr = models.Blog.checkapiPass(apiPass)
                if not cr[0]:
                    errmsg = cr[1]
                    break
                apiPassag = self.param('apiPassag')
                if apiPass != apiPassag:
                    ermsg = 'Password is not the same.'
                    break
            try:
                self.blog.blogDesc = utils.toDBString(blogDesc)
                self.blog.blogName = utils.toDBString(blogName)
                self.blog.postsPerPage = int(postsPerPage)
                self.blog.rssCount = int(rssCount)
                self.blog.postsPerPageList = int(postsPerPageList)
                self.blog.widgets = widgets
                self.blog.theme = theme

                self.theme = theme
                self.templatedic['theme'] = theme
                # widgets
                models.Blog.attachWidgets(self.templatedic, self.blog.widgets)

                if changeAPIPass:
                    self.blog.setAPIPassword(apiPass)
                self.blog.put()
            except Exception,e:
                errmsg = str(e)
                break
            haserr = False
            infomsg = 'Setting saved.'
            break
        
        self.templatedic['errmsg'] = errmsg
        self.templatedic['infomsg'] = infomsg
        if haserr:
            self.templatedic['blogName'] = self.param('blogName')
            self.templatedic['blogDesc'] = self.param('blogDesc')
            self.templatedic['postsPerPage'] = self.param('postsPerPage')
            self.templatedic['rssCount'] = self.param('rssCount')
            self.templatedic['postsPerPageList'] = self.param('postsPerPageList')
            self.templatedic['changeAPIPass'] = self.param('changeAPIPass')
            self.templatedic['apiPass'] = self.param('apiPass')
            self.templatedic['apiPassag'] = self.param('apiPassag')
            self.templatedic['themename'] = self.param('themename')
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = self.param('widgets')
        else:
            self.templatedic['blogName'] = blogName
            self.templatedic['blogDesc'] = blogDesc
            self.templatedic['postsPerPage'] = postsPerPage
            self.templatedic['rssCount'] = rssCount
            self.templatedic['postsPerPageList'] = postsPerPageList
            self.templatedic['themename'] = theme.name
            self.templatedic['themelist'] = models.Theme.getAllThemes()
            self.templatedic['widgets'] = '\n'.join(widgets)
            if changeAPIPass:
                self.templatedic['changeAPIPass'] = changeAPIPass
                self.templatedic['apiPass'] = apiPass
                self.templatedic['apiPassag'] = apiPassag

        self.render(models.Theme.Settings_page)
        return
class GlogWidget(base.RequestHandler.PageRequestHandler):
    def get(self):
        wstr = self.reqpath[len('/widget/'):]
        return self.deal(wstr)

    def deal(self, wstr):
        w = wstr.split('/',1)
        if len(w) > 1:
            # has parameter
            wid = w[0]
            params = w[1].split('/')
        else:
            # no parameter
            wid = w[0]
            params = []

        self.dealWidget(wid, params)
        return
    
    def dealWidget(self, wid, params):
        wf = widgets.getWidget(wid)
        if wf and callable(wf):
            wf(self, params)
        else:
            raise base.Error.PageNotFoundError('no this widget [%s]' % wid)

        self.render(wid + ".widget")
        return

class BlogWidget(GlogWidget):
    @base.Decorators.blogRequest(blogid_re)
    def get(self):
        wstr = self.blogpath[len('/widget/'):]
        return self.deal(wstr)
    pass

    
app = webapp2.WSGIApplication([
    (AppEnv.apppath + '/?', GlogIndexPage),
    (AppEnv.apppath + '/archive/.+', GlogIndexPage),
    (AppEnv.apppath + '/tag/.+', GlogIndexPage),
    (AppEnv.apppath + '/rss/comment(/.*)*', GlogCommentFeed),
    (AppEnv.apppath + '/rss(/.*)*', GlogRssFeed),
    (AppEnv.apppath + '/widget/.+', GlogWidget),
    (AppEnv.apppath + '/\w+/?',PostList ),
    (AppEnv.apppath + '/\w+/summary', PostSummary),
    (AppEnv.apppath + '/\w+/summary/.*', PostSummary),
    (AppEnv.apppath + '/\w+/new/?', NewPost),
    (AppEnv.apppath + '/\w+/edit', EditPost),
    (AppEnv.apppath + '/\w+/edit/.+', EditPost),
    (AppEnv.apppath + '/\w+/post/.+',ViewPost),
    (AppEnv.apppath + '/\w+/del/.+', DeletePost),
    (AppEnv.apppath + '/\w+/comment/.+', AddComment),
    (AppEnv.apppath + '/\w+/archive/.+', PostList),
    (AppEnv.apppath + '/\w+/tag/.+', PostList),
    (AppEnv.apppath + '/\w+/rss/comment(/.*)*', CommentFeed),
    (AppEnv.apppath + '/\w+/rss(/.*)*', RssFeed),
    #(AppEnv.apppath + '/\w+/track/.+', TrackPost),
    (AppEnv.apppath + '/\w+/settings', Settings),
    (AppEnv.apppath + '/\w+/widget/.+', BlogWidget),
    ('.*', base.RequestHandler.HTTP404),
], debug=AppEnv.debug)
